//
// Created by LiuYou on 2021/11/25.
//

#ifndef HTTP_SERVER_MUTEXLOCK_HPP
#define HTTP_SERVER_MUTEXLOCK_HPP


#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <stdexcept>


/**
 * @brief 线程同步机制包装类 -> MutexLock
 *
 * @details 使用了 RAII(资源获取即为初始化) 的手法封装了 pthread 库的 pthread_mutex_t, 以对象管理了资源。
 * <p>MutexLock类为一个资源管理类, 所以提供了对原始资源的访问。
 * 另外, 由于这个类的RAII对象被复制不合理。所以使用 = delete;</p>
 *
 * @note 没有考虑异常。
 * @see Cond类, Sem类。
 * @since 0.1
 *
 * @author ly
 *
 * @version 0.1.1
 */
class MutexLock final {
public:
    MutexLock() {
        int errNum = pthread_mutex_init( &mutex, nullptr );
        if (errNum != 0) {
            fprintf( stderr, "pthread_mutex_init(): %s.\n", strerror( errNum ));
//            throw std::runtime_error( std::string( "pthread_mutex_init(): " ) + strerror( errNum ) + "." );
        }
    }

    ~MutexLock() {
        pthread_mutex_destroy( &mutex );
    }

    MutexLock(const MutexLock& rhs) = delete;

    MutexLock& operator=(const MutexLock& rhs) = delete;

    bool lock() {
        int errNum = pthread_mutex_lock( &mutex );
        if (errNum != 0) {
            fprintf( stderr, "pthread_mutex_lock(): %s.\n", strerror( errNum ));
            return false;
        }
        return true;
    }

    bool unlock() {
        int errNum = pthread_mutex_unlock( &mutex );
        if (errNum != 0) {
            fprintf( stderr, "pthread_mutex_unlock(): %s.\n", strerror( errNum ));
            return false;
        }
        return true;
    }

    const pthread_mutex_t& getMutex() const {
        return mutex;
    }

    pthread_mutex_t& getMutex() {
        return mutex;
    }

private:
    pthread_mutex_t mutex{};

};


/**
 * @brief 互斥锁的使用类。以 RAII 的手法封装了互斥锁的使用。
 * @details 将 加锁和解锁封装成了一个对象, 这样如果加锁后的代码出现了异常,
 * 那么在异常的栈展开过程中, 会自动调用析构函数, 而析构函数就解锁了。这样就避免只加锁, 不解锁这种错误了。
 *
 * @author ly
 * @since 0.1.1
 */
class MutexLockGuard final {
public:
    MutexLockGuard(MutexLock& mutexLock) : mutexLock( mutexLock ) {
        mutexLock.lock();
    }

    virtual ~MutexLockGuard() {
        mutexLock.unlock();
    }

private:
    MutexLock& mutexLock;

};


#endif //HTTP_SERVER_MUTEXLOCK_HPP
